﻿using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Numerics;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Cryptography;

namespace WebServiceRequester
{
    public partial class WebFormServiceRSA : System.Web.UI.Page
    {
        private int rsa_p = 0;
        private int rsa_q = 0;
        private int rsa_n = 0;
        private int rsa_phin = 0;
        private int rsa_c = 0;
        private int rsa_d = 0;
        private static int max = 30000;

        // Declare web service reference
        private ServiceNombrePremier.WebServiceNombrePremierSoapClient wsNbrPrem;
        private ServicePGCD.WebServiceMathSoapClient wsPGCD;

        protected void Page_Load(object sender, EventArgs e)
        {
            // Create instance of Nombre premier Service
            wsNbrPrem = new ServiceNombrePremier.WebServiceNombrePremierSoapClient();
            wsPGCD = new ServicePGCD.WebServiceMathSoapClient();

            if (!this.IsPostBack)
            {
                int indP, indQ;
                List<int> listTemp;
                Random rd = new Random();

                // Getting primary numbers
                listTemp = wsNbrPrem.PremiersRange(1, max).ToList<Int32>();

                do {
                    // Generate indice p and indice q
                    indP = rd.Next(listTemp.Count - 1);
                    do
                    {
                        indQ = rd.Next(listTemp.Count - 1);
                    } while (indP == indQ);

                    // Getting p and q
                    rsa_p = listTemp.ElementAt<int>(indP);
                    rsa_q = listTemp.ElementAt<int>(indQ);

                    // Calculate n, and phi(n)
                    rsa_n = rsa_p * rsa_q;
                    rsa_phin = (rsa_p - 1) * (rsa_q - 1);

                    // Calculate e
                    do
                    {
                        rsa_c = rd.Next(1, max-1);
                    } while (wsPGCD.PGCD(rsa_phin, rsa_c) != 1);
                

                    // Calculate d
                    rsa_d = Bezout(rsa_phin, rsa_c);

                } while (rsa_c <= 1 || rsa_d <= 1 || rsa_d == rsa_c);

                HttpContext.Current.Session["rsa_p"] = rsa_p;
                HttpContext.Current.Session["rsa_q"] = rsa_q;
                HttpContext.Current.Session["rsa_n"] = rsa_n;
                HttpContext.Current.Session["rsa_phin"] = rsa_phin;
                HttpContext.Current.Session["rsa_c"] = rsa_c;
                HttpContext.Current.Session["rsa_d"] = rsa_d;
            }
            else
            {
                rsa_p = (int)(HttpContext.Current.Session["rsa_p"]);
                rsa_q = (int)(HttpContext.Current.Session["rsa_q"]);
                rsa_n = (int)(HttpContext.Current.Session["rsa_n"]);
                rsa_phin = (int)(HttpContext.Current.Session["rsa_phin"]);
                rsa_c = (int)(HttpContext.Current.Session["rsa_c"]);
                rsa_d = (int)(HttpContext.Current.Session["rsa_d"]);
            }

            // Show result
            lbl_p.Text = rsa_p.ToString();
            lbl_q.Text = rsa_q.ToString();
            lbl_phin.Text = rsa_phin.ToString();
            lbl_publicKey.Text = "(" + rsa_n + "," + rsa_c + ")";
            lbl_privateKey.Text = "(" + rsa_n + "," + rsa_d + ")";

        }

        // Tools

        public int Bezout(int a, int b)
        {
            //Var
            int q, aux;

            //Init
            int r = a; 
            int r1 = b;
            int u = 1; 
            int u1 = 0;
            int v = 0; 
            int v1 = 1;

            while (r1 != 0)
            {
                q = iquo(r, r1);
                aux = r; 
                r = r1;
                r1 = aux - r1 * q;
                aux = u; 
                u = u1; 
                u1 = aux - u1 * q;
                aux = v; 
                v = v1; 
                v1 = aux - v1 * q;
            }

            return v;
        }


        private int iquo(int a, int b)
        {
          return ((int)Math.Floor((double)(a/b)));
        }

        private String Crypt(int mess)
        {
            return BigInteger.ModPow(mess, rsa_c, rsa_n).ToString();
        }

        private String Decrypt(int mess)
        {
            return BigInteger.ModPow(mess, rsa_d, rsa_n).ToString();
        }

        // Actions

        protected void btn_crypt_Click(object sender, EventArgs e)
        {
            int mess;
            if (Int32.TryParse(txt_cryptMess.Text, out mess))
                lbl_cryptResult.Text = Crypt(mess);
        }

        protected void btn_decrypt_Click(object sender, EventArgs e)
        {
            int mess;
            if (Int32.TryParse(txt_decryptMess.Text, out mess))
                lbl_decryptResult.Text = Decrypt(mess);
        }
    }
}